package teleradiologia.web;

import java.awt.image.BufferedImage;
import java.io.File;
import java.io.IOException;
import java.text.DateFormat;
import java.text.ParseException;
import java.text.SimpleDateFormat;
import java.util.Date;
import java.util.HashMap;
import java.util.HashSet;
import java.util.List;
import java.util.Map;
import java.util.Random;
import java.util.Set;

import javax.imageio.ImageIO;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;

import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
import org.hsqldb.lib.Iterator;
import org.springframework.security.context.SecurityContextHolder;
import org.springframework.stereotype.Controller;
import org.springframework.util.Assert;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestParam;
import org.springframework.web.multipart.MultipartFile;
import org.springframework.web.multipart.MultipartHttpServletRequest;
import org.springframework.web.servlet.ModelAndView;
import org.springframework.web.servlet.mvc.SimpleFormController;

import teleradiologia.domain.Customer;
import teleradiologia.domain.Diagnosticlab;
import teleradiologia.domain.Offer;
import teleradiologia.domain.Ordering;
import teleradiologia.domain.Ordertype;
import teleradiologia.domain.Patient;
import teleradiologia.domain.Person;
import teleradiologia.domain.Picture;
import teleradiologia.domain.Technician;
import teleradiologia.service.DiagnosticlabManipulator;
import teleradiologia.service.DiagnosysManipulator;
import teleradiologia.service.OfferManipulator;
import teleradiologia.service.OrderingManipulator;
import teleradiologia.service.OrdertypeManipulator;
import teleradiologia.service.PatientManipulator;
import teleradiologia.service.PersonManipulator;
import teleradiologia.service.PictureManipulator;
import teleradiologia.service.TechnicianManipulator;
import teleradiologia.utils.PatientWarnings;
import teleradiologia.utils.Validation;

@Controller
public class TechnicianController extends SimpleFormController {

	private static final Log log = LogFactory
			.getLog(TechnicianController.class);

	private PersonManipulator personManipulator;
	private TechnicianManipulator technicianManipulator;
	private OrderingManipulator orderingManipulator;
	private OrdertypeManipulator ordertypeManipulator;
	private DiagnosticlabManipulator diagnosticlabManipulator;
	private PatientManipulator patientManipulator;
	private DiagnosysManipulator diagnosysManipulator;
	private PictureManipulator pictureManipulator;
	private OfferManipulator offerManipulator;

	public OfferManipulator getOfferManipulator() {
		return offerManipulator;
	}

	public void setOfferManipulator(OfferManipulator offerManipulator) {
		this.offerManipulator = offerManipulator;
	}

	@RequestMapping("/technician/technicianHome.htm")
	public ModelAndView handleTechnicianHome() {

		return new ModelAndView("technician/technicianHome");
	}

	@RequestMapping("/technician/addOrderingHome.htm")
	public ModelAndView handleAddOrderingHome() {

		Person me = ((Person) SecurityContextHolder.getContext()
				.getAuthentication().getPrincipal());

		me = personManipulator.getById(me.getId());

		HashMap<String, Object> myModel = new HashMap<String, Object>();

		myModel.put("ordertype", this.ordertypeManipulator.getAll());
		myModel.put("technitian", this.technicianManipulator.geByIdPerson(me
				.getId()));
		myModel.put("diagnosticlab", this.diagnosticlabManipulator.getAll());
		myModel.put("patient", this.patientManipulator.getAll());

		ModelAndView result = new ModelAndView("technician/addOrderingHome",
				"model", myModel);

		return result;
	}

	public ModelAndView handleAddOrderingHomeOrdertype(Ordertype ordertype) {

		log.info("ordertype");
		Person me = ((Person) SecurityContextHolder.getContext()
				.getAuthentication().getPrincipal());

		me = personManipulator.getById(me.getId());

		HashMap<String, Object> myModel = new HashMap<String, Object>();

		List<Object[]> results = this.diagnosticlabManipulator
				.getAllByOrdertype(ordertype);
		Set<Diagnosticlab> diagnosticlabs = new HashSet<Diagnosticlab>(0);
		Set<Offer> offers = new HashSet<Offer>(0);

		for (int i = 0; i < results.size(); i++) {
			Diagnosticlab tmp = this.diagnosticlabManipulator
					.getByKrsnumber((String) results.get(i)[0]);
			diagnosticlabs.add(tmp);

			Offer offer = this.offerManipulator
					.getById((Long) results.get(i)[1]);
			offers.add(offer);
		}

		myModel.put("ordertype", this.ordertypeManipulator.getAll());
		myModel.put("ordertype2", ordertype);
		myModel.put("technitian", this.technicianManipulator.geByIdPerson(me
				.getId()));
		myModel.put("diagnosticlab", diagnosticlabs);
		myModel.put("offer", offers);
		myModel.put("patient", this.patientManipulator.getAll());

		ModelAndView result = new ModelAndView("technician/addOrderingHome",
				"model", myModel);

		return result;
	}

	@RequestMapping("/technician/selectOrdertype.htm")
	public ModelAndView handleSelectOrdertype(
			@RequestParam("addIdordertype") long idordertype) {

		Ordertype ordertype = this.ordertypeManipulator.getById(idordertype);

		return handleAddOrderingHomeOrdertype(ordertype);
	}

	@SuppressWarnings("unchecked")
	@RequestMapping("/technician/addOrderingPictures.htm")
	public ModelAndView handleAddOrdering(
			HttpServletRequest request,
			HttpServletResponse response,
			@RequestParam("addKrsDiagnosticlab") String krsDiagnosticlab,
			@RequestParam("addIdordertype") long idordertype,
			@RequestParam("addIdpatient") long idpatient,
			@RequestParam("addAdditionalinformations") String additionalinformations)
			throws IllegalStateException, IOException {

		Assert.state(request instanceof MultipartHttpServletRequest,
				"request !instanceof MultipartHttpServletRequest");
		final MultipartHttpServletRequest multiRequest = (MultipartHttpServletRequest) request;

		final Map files = multiRequest.getFileMap();

		// Dodawanie danych zlecenia
		Person me = ((Person) SecurityContextHolder.getContext()
				.getAuthentication().getPrincipal());

		me = personManipulator.getById(me.getId());

		Technician technician = this.technicianManipulator.geByIdPerson(me
				.getId());

		Ordering ordering = new Ordering();
		ordering.setOrderdate(new Date());
		ordering.setAdditionalinformations(additionalinformations);
		ordering.setStatus("zlecony");
		Patient patient = this.patientManipulator.getById(idpatient);
		Customer customer = technician.getRadiologylab().getCustomer();
		Ordertype ordertype = this.ordertypeManipulator.getById(idordertype);
		Diagnosticlab diagnosticlab = this.diagnosticlabManipulator
				.getByKrsnumber(krsDiagnosticlab);

		// ------------
		long orderID = this.orderingManipulator.create(ordering, patient,
				customer, ordertype, diagnosticlab, technician);

		Ordering persistentOrdering = this.orderingManipulator.getById(orderID);
		// ------------

		log.info("files: " + files.size());
		// OBSLUGA PLIKOW
		for (int i = 1; i <= files.size() / 2; i++) {
			Random r = new Random();

			String jpgFileName = "plik_jpg_" + r.nextInt(1000000) + ".jpg";
			String relativeJpgPath = "../files/jpg/" + jpgFileName;

			String jpgThumbFileName = "miniaturka_" + r.nextInt(100000)
					+ ".jpg";
			String relativeJpgThumbPath = "../files/jpg/" + jpgThumbFileName;

			File jpgPath = new File(request.getSession().getServletContext()
					.getRealPath("/files/jpg"), jpgFileName);

			File jpgThumbPath = new File(request.getSession()
					.getServletContext().getRealPath("/files/jpg"),
					jpgThumbFileName);

			File dicomPath = new File(request.getSession().getServletContext()
					.getRealPath("/files/dicom"), "dicom_" + r.nextInt(1000000));

			MultipartFile mf = ((MultipartFile) files.get("jpg" + (i)));

			String relativeDicomPath = "../files/jpg/" + dicomPath.getName();
			if (mf != null) {
				BufferedImage jpg = ImageIO.read(mf.getInputStream());
				if (jpg != null) {
					Picture picture = new Picture();
					picture.setDicompath(relativeDicomPath);
					picture.setJpgpath(relativeJpgPath);
					picture.setThumbnailpath(relativeJpgThumbPath);
					picture.setTechnician(technician);

					long pictureID = this.pictureManipulator.create(picture);

					Picture persistentPicture = this.pictureManipulator
							.getById(pictureID);

					persistentOrdering.addPicture(persistentPicture);
					this.orderingManipulator.update(persistentOrdering);

					// dicom zapisujemy bez zmian
					((MultipartFile) files.get("dicom" + (i)))
							.transferTo(dicomPath);

					BufferedImage thumbJpg = Utils.scaleImage(jpg, 100, jpg
							.getHeight()
							* 100 / jpg.getWidth());

					// jpegi dopiero po zmianie rozmiarow
					ImageIO.write(jpg, "jpg", jpgPath);
					ImageIO.write(thumbJpg, "jpg", jpgThumbPath);
				}
			}

			// KONIEC OBSLUGI PLIKOW

		}

		return handleManipulateOrderings();
	}

	@RequestMapping("/technician/myOrderings.htm")
	public ModelAndView handleManipulateOrderings() {

		Person me = ((Person) SecurityContextHolder.getContext()
				.getAuthentication().getPrincipal());

		me = personManipulator.getById(me.getId());

		HashMap<String, Object> myModel = new HashMap<String, Object>();

		String nip = this.technicianManipulator.geByIdPerson(me.getId())
				.getNip();
		this.orderingManipulator.updateToTechnicianAchive(nip);

		myModel.put("orderings", this.orderingManipulator
				.getAllByTechnician(nip));

		ModelAndView result = new ModelAndView(
				"technician/manipulateOrderings", "model", myModel);

		return result;
	}

	@RequestMapping("/technician/manipulateArchiveOrderingsHome.htm")
	public ModelAndView handleManipulateArchiveOrderings() {

		Person me = ((Person) SecurityContextHolder.getContext()
				.getAuthentication().getPrincipal());

		me = personManipulator.getById(me.getId());

		HashMap<String, Object> myModel = new HashMap<String, Object>();
		String nip = this.technicianManipulator.geByIdPerson(me.getId())
				.getNip();

		myModel.put("orderings", this.orderingManipulator
				.getAllByTechnician(nip));

		ModelAndView result = new ModelAndView(
				"technician/manipulateArchiveOrderings", "model", myModel);

		return result;
	}

	@RequestMapping("/technician/orderingDetails.htm")
	public ModelAndView handleOrderingDetails(
			@RequestParam("orderingDetailsId") long id) {

		HashMap<String, Object> myModel = new HashMap<String, Object>();

		Ordering ordering = this.orderingManipulator.getById(id);
		myModel.put("ordering", ordering);
		myModel.put("pictures", ordering.getPictures());

		ModelAndView result = new ModelAndView("technician/orderingDetails",
				"model", myModel);

		return result;
	}

	@RequestMapping("/technician/deleteOrdering.htm")
	public ModelAndView handleDeleteOrdering(
			@RequestParam("deleteOrderingId") long id) {
		Ordering ordering = this.orderingManipulator.getById(id);
		this.orderingManipulator.delete(ordering);

		return handleManipulateOrderings();
	}

	@RequestMapping("/technician/deleteArchiveOrdering.htm")
	public ModelAndView handleDeleteArchiveOrdering(
			@RequestParam("deleteOrderingId") long id) {
		Ordering ordering = this.orderingManipulator.getById(id);
		this.orderingManipulator.delete(ordering);

		return handleManipulateArchiveOrderings();
	}

	@RequestMapping("/technician/moveToArchive.htm")
	public ModelAndView handleMoveToArchive(
			@RequestParam("moveToArchiveId") long id) {

		Ordering ordering = this.orderingManipulator.getById(id);
		ordering.setStatus("archiwalne");
		this.orderingManipulator.update(ordering);

		return handleManipulateOrderings();
	}

	@RequestMapping("/technician/myPatients.htm")
	public ModelAndView handleManipulatePatients() {

		HashMap<String, Object> myModel = new HashMap<String, Object>();

		myModel.put("patients", this.patientManipulator.getAll());

		ModelAndView result = new ModelAndView("technician/manipulatePatients",
				"model", myModel);

		return result;
	}

	@RequestMapping("/technician/addPatientHome.htm")
	public ModelAndView handleAddPatientHome() {
		HashMap<String, Object> myModel = new HashMap<String, Object>();
		String isEnabled = "true";

		myModel.put("isEnabled", isEnabled);

		return new ModelAndView("technician/addPatientHome", "model", myModel);
	}

	@RequestMapping("/technician/addPatientHomeValidation.htm")
	public ModelAndView handleAddPatientHomeValidation(
			@RequestParam("patientWarnings") PatientWarnings patientWarnings,
			@RequestParam("patient") Patient patient) {

		HashMap<String, Object> myModel = new HashMap<String, Object>();

		String isMan;
		String isWoman;
		String isEnabled;

		if (patient.getSex() == 'm') {
			isMan = "true";
			isWoman = "false";
		} else {
			isWoman = "true";
			isMan = "false";
		}

		if (patient.getPerson().isEnabled()) {
			isEnabled = "true";
		} else {
			isEnabled = "false";
		}

		myModel.put("patient", patient);
		myModel.put("isMan", isMan);
		myModel.put("isWoman", isWoman);
		myModel.put("isEnabled", isEnabled);
		myModel.put("patientWarnings", patientWarnings);

		return new ModelAndView("technician/addPatientHome", "model", myModel);
	}

	@RequestMapping("/technician/addPatient.htm")
	public ModelAndView handleAddPatient(
			@RequestParam("addPersonName") String name,
			@RequestParam("addPersonSurname") String surname,
			@RequestParam("addPersonLogin") String login,
			@RequestParam("addPersonPassword") String password,
			@RequestParam("addPersonPasswordRep") String passwordRep,
			@RequestParam("addPersonEmail") String email,
			@RequestParam("addPersonEnabled") String enabled,
			@RequestParam("addPatientPesel") String pesel,
			@RequestParam("addPatientSex") String sex,
			@RequestParam("addPatientBirthdate") String birthdate)
			throws ParseException {

		Person person = new Person();

		person.setName(name);
		person.setSurname(surname);
		person.setLogin(login);
		person.setPassword(password);
		person.setEmail(email);
		person.setAuthority("ROLE_PATIENT");

		if (enabled.equals("off")) {
			person.setEnabled(false);
		} else {
			person.setEnabled(true);
		}

		Patient patient = new Patient();

		log.info("enabled: " + enabled);
		log.info("sex: " + sex);

		if (sex.equals("Man")) {
			patient.setSex('m');
		} else if (sex.equals("Woman")) {
			patient.setSex('k');
		} else {
			patient.setSex('x');
		}

		patient.setPesel(pesel);

		PatientWarnings patientWarnings = new PatientWarnings(Validation
				.validatePesel(pesel), Validation.validateEmail(email),
				Validation.validateDate(birthdate), "", Validation
						.validatePassword(password, passwordRep), "");

		if (patientWarnings.isEmpty()) {
			DateFormat df = new SimpleDateFormat("dd-MM-yyyy");
			patient.setBirthdate(df.parse(birthdate));
			patientManipulator.create(patient, person, new Customer());

			// Wyslanie maila

			Email mail = new NewAccountConfirmationEmail(login, password, email);

			try {
				MailSender.sendMail(mail);
			} catch (Exception e) {
				// TODO Auto-generated catch block
				e.printStackTrace();
			}

			return handleManipulatePatients();
		} else {
			patient.setPerson(person);
			patient.setStringDate(birthdate);
			return handleAddPatientHomeValidation(patientWarnings, patient);
		}
	}

	@RequestMapping("/technician/patientDetails.htm")
	public ModelAndView handlePatientDetails(
			@RequestParam("patientDetailsId") long id) {

		HashMap<String, Object> myModel = new HashMap<String, Object>();

		myModel.put("patient", this.patientManipulator.getById(id));

		ModelAndView result = new ModelAndView("technician/patientDetails",
				"model", myModel);

		return result;
	}

	@RequestMapping("/technician/editPatient.htm")
	public ModelAndView handleEditPatient(@RequestParam("editPatientId") long id) {

		HashMap<String, Object> myModel = new HashMap<String, Object>();

		Patient patient = this.patientManipulator.getById(id);
		patient.setStringDate(patient.getBirthdate().toString());

		String isMan;
		String isWoman;

		if (patient.getSex() == 'm') {
			isMan = "true";
			isWoman = "false";
		} else if (patient.getSex() == 'k') {
			isWoman = "true";
			isMan = "false";
		} else {
			isWoman = "false";
			isMan = "false";
		}

		myModel.put("patient", patient);
		myModel.put("isMan", isMan);
		myModel.put("isWoman", isWoman);

		ModelAndView result = new ModelAndView("technician/editPatient",
				"model", myModel);

		return result;
	}

	@RequestMapping("/technician/editPatientValidation.htm")
	public ModelAndView handleEditPatientValidation(
			@RequestParam("patientWarnings") PatientWarnings patientWarnings,
			@RequestParam("patient") Patient patient) {

		HashMap<String, Object> myModel = new HashMap<String, Object>();

		String isMan;
		String isWoman;

		if (patient.getSex() == 'm') {
			isMan = "true";
			isWoman = "false";
		} else if (patient.getSex() == 'k') {
			isWoman = "true";
			isMan = "false";
		} else {
			isWoman = "false";
			isMan = "false";
		}

		myModel.put("patient", patient);
		myModel.put("isMan", isMan);
		myModel.put("isWoman", isWoman);
		myModel.put("patientWarnings", patientWarnings);

		ModelAndView result = new ModelAndView("technician/editPatient",
				"model", myModel);

		return result;
	}

	@RequestMapping("/technician/deletePatient.htm")
	public ModelAndView handleDeletePatient(
			@RequestParam("deletePatientId") long id) {
		Patient patient = this.patientManipulator.getById(id);
		this.patientManipulator.delete(patient);

		return handleManipulatePatients();
	}

	@RequestMapping("/technician/changePatientData.htm")
	public ModelAndView handleChangePatientData(
			// parametry person
			@RequestParam("editPersonName") String name,
			@RequestParam("editPersonSurname") String surname,
			@RequestParam("editPersonLogin") String login,
			@RequestParam("editPersonEmail") String email,
			@RequestParam("editPersonEnabled") String enabled,

			// parametry pacjenta
			@RequestParam("editPatientId") long idpatient,
			@RequestParam("editPatientPesel") String pesel,
			@RequestParam("editPatientSex") String sex,
			@RequestParam("editPatientBirthdate") String birthdate)
			throws ParseException {

		Patient patient = this.patientManipulator.getById(idpatient);

		if (enabled.equals("off")) {
			patient.getPerson().setEnabled(false);
		} else {
			patient.getPerson().setEnabled(true);
		}

		if (sex.equals("Man")) {
			patient.setSex('m');
		} else if (sex.equals("Woman")) {
			patient.setSex('k');
		} else {
			patient.setSex('x');
		}

		patient.setPesel(pesel);

		patient.getPerson().setName(name);
		patient.getPerson().setName(name);
		patient.getPerson().setSurname(surname);
		patient.getPerson().setLogin(login);
		patient.getPerson().setEmail(email);

		PatientWarnings patientWarnings = new PatientWarnings(Validation
				.validatePesel(pesel), Validation.validateEmail(email),
				Validation.validateDate(birthdate), "", "", "");

		if (patientWarnings.isEmpty()) {
			DateFormat df = new SimpleDateFormat("dd-MM-yyyy");
			patient.setBirthdate(df.parse(birthdate));
			this.patientManipulator.update(patient);
			return handleManipulatePatients();
		} else {
			patient.setStringDate(birthdate);
			return handleEditPatientValidation(patientWarnings, patient);
		}
	}

	@RequestMapping("/technician/showDiagnosys.htm")
	public ModelAndView handleShowDiagnosys(
			@RequestParam("orderingId") long idOrdering) {

		HashMap<String, Object> myModel = new HashMap<String, Object>();

		myModel.put("diagnosys", this.diagnosysManipulator
				.getByIdOrdering(idOrdering));

		ModelAndView result = new ModelAndView("technician/showDiagnosys",
				"model", myModel);

		return result;
	}

	public void setTechnicianManipulator(
			TechnicianManipulator technicianManipulator) {
		this.technicianManipulator = technicianManipulator;
	}

	public void setOrdertypeManipulator(
			OrdertypeManipulator ordertypeManipulator) {
		this.ordertypeManipulator = ordertypeManipulator;
	}

	public void setOrderingManipulator(OrderingManipulator orderingManipulator) {
		this.orderingManipulator = orderingManipulator;
	}

	public void setPersonManipulator(PersonManipulator personManipulator) {
		this.personManipulator = personManipulator;
	}

	public void setDiagnosticlabManipulator(
			DiagnosticlabManipulator diagnosticlabManipulator) {
		this.diagnosticlabManipulator = diagnosticlabManipulator;
	}

	public void setPatientManipulator(PatientManipulator patientManipulator) {
		this.patientManipulator = patientManipulator;
	}

	public PictureManipulator getPictureManipulator() {
		return pictureManipulator;
	}

	public void setPictureManipulator(PictureManipulator pictureManipulator) {
		this.pictureManipulator = pictureManipulator;
	}

	public void setDiagnosysManipulator(
			DiagnosysManipulator diagnosysManipulator) {
		this.diagnosysManipulator = diagnosysManipulator;
	}

	public DiagnosticlabManipulator getDiagnosticlabManipulator() {
		return diagnosticlabManipulator;
	}

	public DiagnosysManipulator getDiagnosysManipulator() {
		return diagnosysManipulator;
	}

	public TechnicianManipulator getTechnicianManipulator() {
		return technicianManipulator;
	}

	public PersonManipulator getPersonManipulator() {
		return personManipulator;
	}

	public PatientManipulator getPatientManipulator() {
		return patientManipulator;
	}

	public OrdertypeManipulator getOrdertypeManipulator() {
		return ordertypeManipulator;
	}

	public OrderingManipulator getOrderingManipulator() {
		return orderingManipulator;
	}
}
